package com.iot.ic.dao.redis;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import com.iot.ic.model.UserLogin;
import com.iot.ic.utils.vertify.model.UserToken;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * redis存取用户登录信息
 *
 * @author xiuge
 *         2016年8月4日下午8:19:00
 */
@Repository
public class UserRedisDao {

    private static Logger logger = LoggerFactory.getLogger(UserRedisDao.class);

    private static final String KEY_NAME = "accessToken";

    private static final String PREFIX_KEY = "accessToken:";
    @Autowired
    private RedisTemplate<String, UserLogin> redisTemplate;
    @Autowired
    private RedisTemplate<String, UserToken> listTemplate;
    @Value("${systemConfig.tokenExpireDays}")
    private int maxExpire;


    /**
     * 添加登录缓存
     *
     * @param userLogin
     * @return
     */
    public void addLoginCache(UserLogin userLogin) {
        if (userLogin == null)
            return;
        addUserLogin(userLogin);
        addTokenToList(new UserToken(userLogin.getId(), userLogin.getAccessToken()));
    }

    /**
     * 删除一个认证信息
     *
     * @param accessToken
     */
    public void deleteLoginCache(String accessToken) {
        if (accessToken == null)
            return;
        UserLogin userLogin = findLoginUser(accessToken);
        deleteLoginUser(accessToken);
        UserToken userToken = new UserToken(userLogin.getId(), userLogin.getAccessToken());
        deleteAccessToken(userToken);
    }

    /**
     * 根据token，获取userLogin
     *
     * @param accessToken
     * @return
     */
    public UserLogin findLoginUser(String accessToken) {
        if (accessToken == null)
            return null;
        ValueOperations<String, UserLogin> valueOper = redisTemplate.opsForValue();
        UserLogin userLogin =null;
        try {
            userLogin=valueOper.get(PREFIX_KEY + accessToken);
        }catch (Exception ex){
            deleteLoginUser(accessToken);
            logger.warn("accessToken为"+accessToken+"的用户认证缓存读取失败，已删除");
            return null;
        }
        logger.info("redis中读取" + userLogin);
        return userLogin;
    }

    /**
     * 获取所有登录信息列表
     *
     * @return
     */
    public List<UserLogin> findAllLoginInfo() {
        List<UserLogin> userLogins = new ArrayList<>();
        List<UserToken> userTokens = getAccessTokens();
        for (UserToken userToken : userTokens) {
            String accessToken = userToken.getAccessToken();
            UserLogin userLogin = findLoginUser(accessToken);
            if (userLogin != null)
                userLogins.add(userLogin);
            else {
                deleteAccessToken(userToken);//会影响token超时的判断
                logger.warn("accessToken为" + accessToken + "的设备失效，从token列表中清除");
            }
        }
        return userLogins;
    }


    /**
     * 删除全部认证信息
     *
     * @return
     */
    public void deleteAllLogin() {
        List<UserToken> userTokens = getAccessTokens();
        deleteTokens();
        for (UserToken userToken : userTokens) {
            String accessToken = userToken.getAccessToken();
            deleteLoginUser(accessToken);
        }
    }

    /**
     * 删除token列表
     */
    public void deleteTokens() {
        ListOperations<String, UserToken> listOper = listTemplate.opsForList();
        RedisOperations<String, UserToken> redisOperations = listOper.getOperations();
        redisOperations.delete(KEY_NAME);
        logger.info("删除所有token列表");
    }

    /**
     * 删除userLogin
     *
     * @param accessToken
     * @return
     */
    public void deleteLoginUser(String accessToken) {
        if (accessToken == null)
            return;
        ValueOperations<String, UserLogin> valueOper = redisTemplate.opsForValue();
        RedisOperations<String, UserLogin> redisOperations = valueOper.getOperations();
        redisOperations.delete(PREFIX_KEY + accessToken);
        logger.info("redis删除accessToken=" + accessToken + "的设备");
    }

    /**
     * 从token列表中删除token
     *
     * @param accessToken
     * @return
     */
    public boolean deleteAccessToken(String accessToken) {
        if (accessToken == null)
            return false;
        try {
            UserToken userToken = getUserTokenByAccessToken(accessToken);
            if (userToken != null) {
                ListOperations<String, UserToken> listOper = listTemplate.opsForList();
                listOper.remove(KEY_NAME, 1, userToken);
            }

        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 从token列表中删除token
     *
     * @param userToken
     * @return
     */
    public boolean deleteAccessToken(UserToken userToken) {
        if (userToken == null)
            return false;
        try {
            ListOperations<String, UserToken> listOper = listTemplate.opsForList();
            listOper.remove(KEY_NAME, 1, userToken);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 根据accessToken从缓存中获取UserToken
     *
     * @param accessToken
     * @return
     */
    public UserToken getUserTokenByAccessToken(String accessToken) {
        List<UserToken> userTokens = getAccessTokens();
        for (UserToken userToken : userTokens) {
            if (userToken.getAccessToken() != null && accessToken != null) {
                if (userToken.getAccessToken().equals(accessToken))
                    return userToken;
                else
                    continue;
            }
        }
        return null;
    }

    /**
     * 获取token列表
     *
     * @return
     */
    public List<UserToken> getAccessTokens() {
        ListOperations<String, UserToken> listOper = listTemplate.opsForList();
        long size = listOper.size(KEY_NAME);
        List<UserToken> accessTokens = new ArrayList<>();
        try {
            accessTokens=listOper.range(KEY_NAME, 0, size - 1);
        }catch (Exception ex){
            deleteAllLogin();
            logger.error("accesken缓存列表读取失败！所有Token都已清除，将影响所有用户的登录！");
            return null;
        }
        logger.info("获取accessTokens列表");
        return accessTokens;
    }

    /**
     * 添加token到token列表中
     *
     * @param userToken
     * @return
     */
    public boolean addTokenToList(UserToken userToken) {
        if (userToken == null)
            return false;
        try {
            if (userToken != null) {
                ListOperations<String, UserToken> listOper = listTemplate.opsForList();
                listOper.leftPush(KEY_NAME, userToken);
            } else
                return false;
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 添加token
     *
     * @param userLogin
     * @return
     */
    public boolean addUserLogin(UserLogin userLogin) {
        if (userLogin == null)
            return false;
        try {
            String accessToken = userLogin.getAccessToken();
            ValueOperations<String, UserLogin> valueOper = redisTemplate.opsForValue();
            if (accessToken != null) {
                logger.info("redis保存" + userLogin);
                valueOper.set(PREFIX_KEY + accessToken, userLogin, maxExpire, TimeUnit.DAYS);//超时自动删除，列表中的token不删除，可以通过列表中存在来判断token失效
            } else
                logger.warn("accessToken为空，redis保存失败");
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public boolean deleteLoginCacheByUserId(Integer userId) {
        try {
            List<UserToken> userTokens = getAccessTokens();
            for (UserToken userToken : userTokens) {
                if (userToken.getUserId() != null && userId != null) {
                    if (userId == userToken.getUserId()) {
                        deleteLoginCache(userToken.getAccessToken());
                    }
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}